package com.smart.car.member.controller;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.smart.car.common.res.bean.ResponseResult;
import com.smart.car.common.res.entity.MemberInfoVO;
import com.smart.car.common.res.entity.PointsInfo;
import com.smart.car.common.res.exception.BusinessException;
import com.smart.car.member.entity.MemberCard;
import com.smart.car.member.entity.MemberUser;
import com.smart.car.member.entity.MemberVehicle;
import com.smart.car.member.feign.PointsFeignService;
import com.smart.car.member.feign.fallback.MemberBlockHandler;
import com.smart.car.member.feign.fallback.MemberFallBackHandler;
import com.smart.car.member.service.MemberCardService;
import com.smart.car.member.service.MemberUserService;
import com.smart.car.member.service.MemberVehicleService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.transaction.annotation.Transactional;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户模块控制
 * @author zoutao.blog.csdn.net
 * @date: 2021/4/15
 */
@Slf4j
@RefreshScope
@Api(tags = "用户模块")
@RestController
@RequestMapping("")
public class MemberUserController {

    @Autowired
    private MemberUserService memberUserService;

    @Value("${author.age}")
    private String age;
    @Value("${author.nickname}")
    private String nickName;
    @Value("${server.port}")
    private String port;


    /**
     * 演示本地读取配置的方式-以此引出配置中心
     * 不显示在swagger
     */
    @ApiIgnore
    @GetMapping("/read-local-config")
    public ResponseResult testLocalConfig() {
        HashMap<String, String> map = new HashMap<>();
        map.put("appName", nickName);
        map.put("port", port);
        map.put("age",age);
        return ResponseResult.ok(map);
    }

    @ApiIgnore
    @GetMapping("/read-nacos-config")
    public ResponseResult testNacosConfig() {
        HashMap<String, String> map = new HashMap<>();
        map.put("appName", nickName);
        map.put("port", port);
        map.put("age",age);
        return ResponseResult.ok(map);
    }

    /**
     * 提供给远程调用的方法
     * 消息微服务调用
     */
    @ApiOperation(value = "远程调用-查询用户列表")
    @PostMapping(value = "/listFeign")
    public List<MemberUser> listFeign() throws BusinessException {
        List<MemberUser> members = memberUserService.list();
        log.debug("远程查询用户列表：{}  " + members.size());
        return members;
    }

    /**
     * 查询所有用户信息
     * 搭配sentinel限流熔断，或异常快速失败。采用fallback或BackHandler
     */
//    @SentinelResource(value = "list",
//            fallback = "memberFallBack",fallbackClass = MemberFallBackHandler.class)
    @SentinelResource(value = "list",
            blockHandler = "blackException",blockHandlerClass = MemberBlockHandler.class,
            fallback = "memberFallBack",fallbackClass = MemberFallBackHandler.class,
            exceptionsToIgnore = {IllegalArgumentException.class} )
    @ApiOperation(value = "限流案例-查询所有用户信息")
    @GetMapping("/list")
    public ResponseResult<String> list(HttpServletRequest request) {
        //int a = 1 / 0; //出现异常，调用fallback
        List<MemberUser> members = memberUserService.list();
        //log.info("本地查询用户列表：{} " ,members);
        /*获取token中的信息
        Map<String, Object> infoFromToken = new HashMap<>();
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if ("AUTH_TOKEN".equals(cookie.getName())) {
                log.info("用户微服务获得到的cookie信息为:{}",cookie.getValue());
            }
        }*/
        ResponseResult result = new ResponseResult();
        result.setCode(200);
        result.setMsg("查询成功");
        result.setData(members);
        return result;
    }

    @Autowired
    private PointsFeignService pointsFeignService;

    /**
     * 通过用户id获取用户积分信息
     * SentinelResource一个负责流控，FeignClient一个负责熔断降级。
     */
    @ApiOperation(value = "负载均衡-获取用户积分信息")
    @SentinelResource(value = "mypoint/{id}",
            blockHandler = "blackException",blockHandlerClass = MemberBlockHandler.class,
            fallback = "memberFallBack",fallbackClass = MemberFallBackHandler.class
    )
    @GetMapping("/mypoint/{id}")
    public ResponseResult getUserPointsTest(@PathVariable("id") String id) {
        log.info("开始远程调用，去获取该用户的积分信息：{} ",id);
        ResponseResult result = pointsFeignService.getUserPoints(id);
        return result;
    }

    /**
     * 用户开通会员-绑定手机号
     * {"birth":"2009-02-03","fullName":"tomsoon","phone":"13312345678"}
     */
    @ApiOperation(value = "绑定手机号")
    @PostMapping(value = "/memberRegister")
    public ResponseResult<Integer> bindMobile(String json) {
        ResponseResult<Integer> result = new ResponseResult<>();
        log.info("绑定的手机数据为： " + json);
        int rtn = memberUserService.bindMobile(json);
        result.setData(rtn);
        return result;
    }

    /**
     * 通过手机号查询用户当前积分
     * 附带参数校验规则
     */
    @ApiOperation(value = "查询当前积分")
    @GetMapping("/info/{phone}")
    public ResponseResult<MemberUser> info(@Valid @PathVariable("phone") String phone){
        MemberUser user = memberUserService.selectUserByPhone(phone);
        if (ObjectUtil.isNull(user)) {
            return ResponseResult.fail("手机号不存在");
        }
        return ResponseResult.ok(user);
    }

//    //登录成功之后分配一个token，请求其他API服务就需要携带上这个token。————————移至鉴权中心AUTH中了。
//    @ApiOperation(value = "登录")
//    @PostMapping("/login")
//    public Map<String, Object> login(@RequestBody Map<String, String> user) {
//        Map<String, Object> result = new HashMap<String, Object>();
//        Boolean login = user.get("username").equals("test") && user.get("password").equals("1234");
//        if (login) {
//            Map<String, String> info = new HashMap<>();
//            info.put("username", user.get("username"));
//            //String token = JWTUtil.createJWT(UUID.randomUUID().toString(), user.get("username"),null);
//            //info.put("token", token);
//            result.put("200", "登录成功");
//            result.put("info", info);
//        } else {
//            result.put("401", "用户名或密码错误");
//        }
//        return result;
//    }

    /**
     * 演示JWT鉴权服务，跳过鉴权
     */
    @ApiOperation(value = "鉴权案例-不拦截id")
    @GetMapping("/product/{id}")
    public Map<String, Object> login(@PathVariable("id")  String id) {
        log.info("我是vip，我能快速通行！ " + id);
        //这里抛出异常是为了测试spring-cloud-gateway的retry机制是否正常运行
        /*if (StringUtils.isEmpty("")) {
            throw new BusinessException("测试gateway中的重试功能。");
        }*/
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("code", 200);
        result.put("msg", "尊贵的vip无需认证，操作成功。");
        result.put("data", id);
        return result;
    }

    /**
     * 认证中心调用-通过手机号/账户名+密码查询用户信息
     * 实际上这里可以加上刷新token的判断
     */
    @ApiOperation(value = "认证中心-查询用户信息")
    @PostMapping("/query")
    public ResponseResult<MemberUser> queryUser(@Valid @RequestParam("username") String username,
                                                @RequestParam("password")String password){
        MemberUser user = memberUserService.queryUser(username,password);
        if (ObjectUtil.isNull(user)) {
            return ResponseResult.fail(user,"用户名或密码错误！");
        }
        return ResponseResult.ok(user);
    }

    /**
     * TODO 通过用户id查询用户信息
     * @param memberId
     * @return
     */
    @ApiOperation(value = "查询指定用户信息")
    @PostMapping(value = "/getMember")
    public ResponseResult<MemberUser> getMemberInfo(String memberId) throws BusinessException {
        MemberUser member = memberUserService.getMember(memberId);
        return ResponseResult.ok(member);
    }

    @ApiOperation(value = "查询用户是否存在")
    @PostMapping("/checkAddUser")
    public String addUser_Validator(@RequestBody(required = false)
                                    @ApiParam(required = true, name = "user")
                                    @Validated MemberUser user) {
//        if(bindingResult.hasErrors()){
//            for (ObjectError error : bindingResult.getAllErrors()) {
//                return error.getDefaultMessage();
//            }
//        }
        List<MemberUser> users = memberUserService.queryUser(user.getPhone());
        return users.toString();
    }

    //添加
    @ApiOperation(value = "添加用户")
    @GetMapping("/addUser")
    public ResponseResult addUser(@RequestBody @Valid MemberUser user){
        List<MemberUser> userList = memberUserService.queryUser(user.getPhone());
        if(ObjectUtil.isNull(userList))
        {
            memberUserService.insert(user);
            return ResponseResult.ok(user, "添加成功！");
        }
        return ResponseResult.fail(user, "该用户手机号已存在，不允许注册！");
    }

    //编辑
    @ApiOperation(value = "编辑用户")
    @PostMapping("/editUser")
    public ResponseResult editUser(@RequestBody MemberUser user){
        try {
            memberUserService.updateByExampleSelective(user);
        } catch (Exception e) {
            return ResponseResult.fail("修改失败！");
        }
        return ResponseResult.ok(user, "修改成功！");
    }


    @Autowired
    private MemberVehicleService vehicleService;

    //删除
    @ApiOperation(value = "删除用户")
    @Transactional
    @GetMapping("/deleteUser")
    public ResponseResult deleteUser(@RequestParam("uid") String uid)
    {
        MemberUser user = memberUserService.selectUserById(uid);
        if(ObjectUtil.isNotNull(user))
        {
            MemberVehicle userCar = vehicleService.getVehicle(uid);
            if(ObjectUtil.isNotNull(userCar))
            {//正在停车不能删
                return ResponseResult.fail(userCar.getPlateNum(), "正在停车，不能删除！");
            }
            memberUserService.deleteByPrimaryKey(user.getId());
            return ResponseResult.ok("删除成功！");
        }else{
            return ResponseResult.fail(user.getPhone(), "删除失败！");
        }
    }


    @Autowired
    private PointsFeignService pointsInfoService;

    /**
     * 获取用户的信息集合（个人信息，积分信息，车辆信息）
     */
    @ApiOperation(value = "远程调用-获取用户完整信息")
    @PostMapping("/getAllUserInfo")
    public ResponseResult<MemberInfoVO> getUserAll(String memberId) throws BusinessException {
        ResponseResult<MemberInfoVO> result = new ResponseResult<>();
        MemberUser userInfo = memberUserService.getMember(memberId);
        ResponseResult<PointsInfo> userPoints  = pointsInfoService.getData(memberId);
        MemberInfoVO vo = new MemberInfoVO();
        if (ObjectUtil.isNotNull(userInfo)) {
            vo.setId(userInfo.getId());
            vo.setPhone(userInfo.getPhone());
            vo.setRealName(userInfo.getRealName());
            vo.setBirth(userInfo.getBirth());
        }
        if (null != userPoints && null != userPoints.getData()) {
            vo.setCurQty(userPoints.getData().getCurQty());
        }
        result.setData(vo);
        return result;
    }

    @ApiOperation("微服务压测接口")
    @GetMapping("/qpsTest")
    public String test() {
        String dString = UUID.randomUUID().toString();
        log.info("微服务自身的方法，产生的结果是：{}",dString);
        return dString;
    }

}
